import { OriginAnalyser, AnalyserOptions } from './OriginAnalyser';

interface Navigator {
  msGetUserMedia(
    constraints: MediaStreamConstraints,
    successCallback: any,
    errorCallback: any
  ): void;
  mozGetUserMedia(
    constraints: MediaStreamConstraints,
    successCallback: any,
    errorCallback: any
  ): void;
  webkitGetUserMedia(
    constraints: MediaStreamConstraints,
    successCallback: any,
    errorCallback: any
  ): void;
}

export class RecorderAnalyser extends OriginAnalyser {
  private _stream: MediaStream | null = null;
  private _source: MediaStreamAudioSourceNode | null = null;
  constructor(options?: AnalyserOptions) {
    super(options);
  }

  private _getMediaOS(): Promise<MediaStream> {
    const type = { audio: true };
    if (navigator.mediaDevices.getUserMedia) {
      return navigator.mediaDevices.getUserMedia(type);
    }
    const getMedia =
      (navigator as unknown as Navigator).msGetUserMedia ||
      (navigator as unknown as Navigator).mozGetUserMedia ||
      (navigator as unknown as Navigator).webkitGetUserMedia;

    if (getMedia) {
      return new Promise((resolve, reject) => {
        getMedia.call(
          navigator,
          type,
          (stream: MediaStream) => resolve(stream),
          () => reject()
        );
      });
    }
    return Promise.reject();
  }

  private _createSource(stream: MediaStream) {
    this._source = this.audioContext.createMediaStreamSource(stream);
    this._source.connect(this.audioAnalyser);
  }

  async start() {
    try {
      const stream = await this._getMediaOS();
      this._stream = stream;
      this._createSource(stream);
    } catch (error) {
      console.warn('no support recorder');
      return Promise.reject();
    }
  }

  stop() {
    this._stream?.getTracks().forEach((track) => track.stop());
    this._stream = null;
    this._source?.disconnect();
    this._source = null;
  }
}
